package cn.iocoder.yudao.boot.web.advice;

import cn.iocoder.yudao.boot.common.pojo.R;
import cn.iocoder.yudao.boot.common.util.json.JsonUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 全局响应结果（ResponseBody）处理器
 * <p>
 * 不同于在网上看到的很多文章，会选择自动将 Controller 返回结果包上 {@link R}，
 * 在 onemall 中，是 Controller 在返回时，主动自己包上 {@link R}。
 * 原因是，GlobalResponseBodyHandler 本质上是 AOP，它不应该改变 Controller 返回的数据结构
 * <p>
 * 目前，GlobalResponseBodyHandler 的主要作用是，记录 Controller 的返回结果，
 */
@ControllerAdvice
public class GlobalResponseBodyAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        if (returnType.getMethod() == null) {
            return false;
        }
        // 只拦截返回结果为 CommonResult 类型
        return returnType.getMethod().getReturnType() != ResponseEntity.class;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {

        // 数据封装为Result：将接口方法返回的数据，封装到 Result.data 字段中。
        ResponseEntity<Object> result = ResponseEntity.ok(body);
        // 返回类型不是 String：直接返回
        if (returnType.getParameterType() != String.class) {
            return result;
        }

        // 返回类型是 String：不能直接返回，需要进行额外处理
        // 1. 将 Content-Type 设为 application/json ；返回类型是String时，默认 Content-Type = text/plain
        HttpHeaders headers = response.getHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 2. 将 Result 转为 Json字符串 再返回
        // （否则会报错 java.lang.ClassCastException: com.example.core.model.Result cannot be cast to java.lang.String）
        return JsonUtils.toJsonString(ResponseEntity.ok(body));
    }

}
